<?php

namespace DesignPatterns;

use PHPUnit\Framework\TestCase;

// 通过单例模式可以保证系统中,应用该模式(单例模式)的类一个类只有一个实例,即一个类只有一个对象实例
// 对于系统中的某些类来说,只有一个实例很重要。例如,数据库操作类,当我们需要使用数据库操作类进行数据库操作时,我们期望在整个生命周期内,
// 有且只有一实例来进行增删改查

// 单例模式的好处
// 在内存中只有一个对象，节省内存空间。
// 避免频繁的创建销毁对象，可以提高性能。
// 避免对共享资源的多重占用。

// 构建步骤
// 1.私有化构造函数,构造对象只能由单例类自身进行管理
// 2.对外提供获取类实例的静态方法(类实例由静态变量进行保存)
// 3.禁止外部clone对象

final class Singleton
{
    
    private static $instance;
    
    //将构造方法私有化，防止外部new
    private function __construct()
    {
    }
    
    //防止直接克隆对象克隆
    private function __clone()
    {
    }
    
    /**
     * 开放给外部获取实例的方法
     * @return Singleton
     */
    public static function getInstance() : Singleton
    {
        if( !self::$instance instanceof self ) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}


include 'vendor/autoload.php';


class SingletonTest extends TestCase
{
    public function testSingleton()
    {
        $first = Singleton::getInstance();
        $second = Singleton::getInstance();
        
        $refection = new \ReflectionObject( $first );
        $meth = $refection->getMethod('__construct');
        $this->assertTrue($meth->isPrivate());
        
        $this->assertSame($first, $second, 'not true');
        $this->assertSame(spl_object_hash($first), spl_object_hash($second), 'not true');
        $this->assertArrayHasKey('key' , [ 'key'=> 1 ]);
        $this->assertSame($first , $second , 'not same');
        $this->assertContains('aaaa' , 'shdhhdhaaaa');
        $this->assertInstanceOf(Singleton::class, $first,'not instance of \DesignPatterns\Singleton');
    }
    
    public function testPrivateConstructor()
    {
        $obj = Singleton::getInstance();
    
        $refl = new \ReflectionObject($obj);
        $meth = $refl->getMethod('__construct');
        $this->assertTrue($meth->isPrivate());
    }
}